{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### Tensors\n",
    "\n",
    "Tensors 类似于 numpy 中的多维数组(ndarrays)，但它还可以用于 GPU 中实现计算的加速。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个未初始化的 5*3 矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([[1.0102e-38, 1.0561e-38, 1.0469e-38],\n        [1.0653e-38, 1.0469e-38, 6.2449e-39],\n        [1.0561e-38, 1.0653e-38, 1.0286e-38],\n        [9.0918e-39, 4.4082e-39, 8.4489e-39],\n        [4.5918e-39, 4.5000e-39, 1.0561e-38]])\n"
    }
   ],
   "source": [
    "x=torch.empty(5,3)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个随机初始化的 5*3 矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([[0.6646, 0.0466, 0.4164],\n        [0.1609, 0.0778, 0.3384],\n        [0.9071, 0.3227, 0.0137],\n        [0.2167, 0.2532, 0.4306],\n        [0.5620, 0.3881, 0.2397]])\n"
    }
   ],
   "source": [
    "rand_x=torch.rand(5,3)\n",
    "print(rand_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个数值皆是 0，类型为 long 的矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([[0, 0, 0],\n        [0, 0, 0],\n        [0, 0, 0],\n        [0, 0, 0],\n        [0, 0, 0]])\n"
    }
   ],
   "source": [
    "zero_x=torch.zeros(5,3,dtype=torch.long)\n",
    "print(zero_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个 tensor，初始化方式是给定数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([5.5000, 3.0000])\n"
    }
   ],
   "source": [
    "tensor1=torch.tensor([5.5,3])\n",
    "print(tensor1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "根据已存在的 tensor 创建新的 tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([[1., 1., 1.],\n        [1., 1., 1.],\n        [1., 1., 1.],\n        [1., 1., 1.],\n        [1., 1., 1.]], dtype=torch.float64)\n"
    }
   ],
   "source": [
    "tensor2=tensor1.new_ones(5,3,dtype=torch.double)  #new_ 方法需要输入tensor大小\n",
    "print(tensor2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "修改数值类型，但有相同的 size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor3: tensor([[0.8729, 0.8336, 0.9358],\n        [0.8240, 0.3338, 0.9845],\n        [0.4254, 0.3109, 0.7223],\n        [0.4272, 0.5394, 0.3833],\n        [0.3787, 0.7672, 0.7140]])\n"
    }
   ],
   "source": [
    "tensor3=torch.rand_like(tensor2,dtype=torch.float)\n",
    "print('tensor3:',tensor3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获取 tensor 的 size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "torch.Size([5, 3])\n"
    }
   ],
   "source": [
    "print(tensor3.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意**： torch.Size 实际上是元组(tuple)类型，所以支持所有的元组操作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Operations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "加法操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor3 + tensor4= tensor([[1.4236, 1.7354, 1.4045],\n        [1.5753, 0.7696, 1.4616],\n        [0.5245, 1.2040, 0.7877],\n        [1.1813, 0.7593, 0.4332],\n        [0.6712, 0.7673, 1.0277]])\ntensor3 + tensor4= tensor([[1.4236, 1.7354, 1.4045],\n        [1.5753, 0.7696, 1.4616],\n        [0.5245, 1.2040, 0.7877],\n        [1.1813, 0.7593, 0.4332],\n        [0.6712, 0.7673, 1.0277]])\n"
    }
   ],
   "source": [
    "tensor4=torch.rand(5,3)\n",
    "print('tensor3 + tensor4=',tensor3+tensor4)\n",
    "print('tensor3 + tensor4=',torch.add(tensor3,tensor4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "新声明一个 tensor 变量保存加法操作的结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "add result= tensor([[1.4236, 1.7354, 1.4045],\n        [1.5753, 0.7696, 1.4616],\n        [0.5245, 1.2040, 0.7877],\n        [1.1813, 0.7593, 0.4332],\n        [0.6712, 0.7673, 1.0277]])\n"
    }
   ],
   "source": [
    "result=torch.empty(5,3)\n",
    "torch.add(tensor3,tensor4,out=result)\n",
    "print('add result=',result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "直接修改变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor3= tensor([[1.4236, 1.7354, 1.4045],\n        [1.5753, 0.7696, 1.4616],\n        [0.5245, 1.2040, 0.7877],\n        [1.1813, 0.7593, 0.4332],\n        [0.6712, 0.7673, 1.0277]])\n"
    }
   ],
   "source": [
    "tensor3.add_(tensor4)\n",
    "print('tensor3=',tensor3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意**：可以改变 tensor 变量的操作都带有一个后缀 `_`, 例如 x.copy_(y), x.t_() 都可以改变 x 变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以用类似 numpy 的索引操作来访问 tensor 的某一维, 比如访问 tensor3 第一列数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([1.4236, 1.5753, 0.5245, 1.1813, 0.6712])\n"
    }
   ],
   "source": [
    "print(tensor3[:,0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "修改 tensor 大小，可以采用方法 `torch.view`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])\n"
    }
   ],
   "source": [
    "x=torch.randn(4,4)\n",
    "y=x.view(16)\n",
    "#-1表示除给定唯度外的其余维度的乘积\n",
    "z=x.view(-1,8)\n",
    "print(x.size(),y.size(),z.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果 tensor 仅有一个元素，可以采用 `.item()` 来获取类似 Python 中整数类型的数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([1.9367])\n1.9367109537124634\n"
    }
   ],
   "source": [
    "x=torch.randn(1)\n",
    "print(x)\n",
    "print(x.item())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Numpy\n",
    "\n",
    "tensor 和 numpy 的 array 相互转换，并且如果是在 cpu 上的操作，两者转换会共享内存，即改变一个变量同时也改变另一个。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Tensor to Numpy array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([1., 1., 1., 1., 1.])\n"
    }
   ],
   "source": [
    "a=torch.ones(5)\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "[1. 1. 1. 1. 1.]\n"
    }
   ],
   "source": [
    "b=a.numpy()\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "看看改变其中一个变量，另一个变量的改变"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([4., 4., 4., 4., 4.])\n[4. 4. 4. 4. 4.]\n"
    }
   ],
   "source": [
    "a.add_(1)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Numpy Array to Torch Tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "[2. 2. 2. 2. 2.]\ntensor([2., 2., 2., 2., 2.], dtype=torch.float64)\n"
    }
   ],
   "source": [
    "import numpy as np \n",
    "a=np.ones(5)\n",
    "b=torch.from_numpy(a)\n",
    "np.add(a,1,out=a)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 CPU 上，除了 CharTensor 外，都支持和 Numpy 的 array 的互相转换"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### CUDA Tensors\n",
    "\n",
    "Tensors 可以通过采用 `.to` 方法来转换到不同设备上"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "tensor([2.9367], device='cuda:0')\ntensor([2.9367], dtype=torch.float64)\n"
    }
   ],
   "source": [
    "if torch.cuda.is_available():\n",
    "    device=torch.device(\"cuda\")   #定义一个CUDA设备对象\n",
    "    y=torch.ones_like(x,device=device)  #显示创建在GPU上的一个tensor\n",
    "    x=x.to(device)                     #也可以采用.to(\"cuda\")\n",
    "    z=x+y\n",
    "    print(z)\n",
    "    print(z.to(\"cpu\",torch.double))        #.to()方法也可以改变数值类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13-final"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}